package cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.genre;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.wicket.RestartResponseException;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.event.IEvent;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.spring.injection.annot.SpringBean;

import cz.muni.fi.pa165.musiclibrary.api.service.IGenreService;
import cz.muni.fi.pa165.musiclibrary.api.service.ISongService;
import cz.muni.fi.pa165.musiclibrary.api.service.auth.IUser;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.IAlbumDTO;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.IGenreDTO;
import cz.muni.fi.pa165.musiclibrary.api.service.dto.ISongDTO;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.MusicLibrarySession;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.ConfirmationLink;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.FormSubmittedEvent;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.components.GenreFormPanel;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.AbstractMusicLibraryPage;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.album.AlbumPage;
import cz.muni.fi.pa165.musiclibrary.musiclibraryweb.pages.search.SearchPage;

/**
 *
 * @author Maros Kucbel
 * @date 2012-11-29T19:48:33+0100
 */
public final class GenrePage extends AbstractMusicLibraryPage {

    @SpringBean
    private IGenreService genreService;
    @SpringBean
    private ISongService songService;
    
    /**
     * Constructor.
     */
    public GenrePage() {
        this(new PageParameters());
    }
    
    /**
     * Constructor
     * @param pageParameters Parameters for page initialization.
     */
    public GenrePage(final PageParameters pageParameters) {
        super(pageParameters);
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();
        this.initComponents();
    }
    
    private void initComponents() {
        Long id = this.getPageParameters().get("id").toOptionalLong();
        if (id == null) {
            throw new RestartResponseException(SearchPage.class);
        }
        final IGenreDTO genre = this.genreService.getById(id);
        if (genre == null) {
            throw new RestartResponseException(SearchPage.class);
        }
        this.add(new Label(ComponentIDs.GENRE_NAME, genre.getName()));
        ListView<IAlbumDTO> albums = new ListView<IAlbumDTO>(ComponentIDs.ALBUMS_VIEW, this.getAlbums(genre)) {

            @Override
            protected void populateItem(ListItem<IAlbumDTO> item) {
                IAlbumDTO album = item.getModelObject();
                PageParameters params = new PageParameters();
                params.add("id", album.getIdAlbum().toString());
                Link<Void> albumLink = new BookmarkablePageLink<Void>(ComponentIDs.ALBUM_LINK, AlbumPage.class, params);
                albumLink.add(new Label(ComponentIDs.ALBUM_LINK_NAME, album.getTitle()));
                item.add(albumLink);
            }
        };
        this.add(albums);
        
        MusicLibrarySession session = MusicLibrarySession.get();
        final ModalWindow genreWindow = new ModalWindow(ComponentIDs.EDIT_GENRE_MODAL) {
            
            @Override
            public void show(AjaxRequestTarget target) {
                this.setContent(new GenreFormPanel(this.getContentId(), genre));
                super.show(target);
            }
        };
        this.add(genreWindow);
        genreWindow.setTitle(new StringResourceModel("GenrePage.editGenre.modal.title", this, null));
        genreWindow.setMinimalWidth(500);
        genreWindow.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
        AjaxLink editGenre = new AjaxLink(ComponentIDs.EDIT_GENRE_MODAL_LINK) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                genreWindow.show(target);
            }

            @Override
            public void onEvent(IEvent<?> event) {
                if (genreWindow.isShown() && event.getPayload() instanceof FormSubmittedEvent) {
                    FormSubmittedEvent submitted = (FormSubmittedEvent) event.getPayload();
                    genreWindow.close(submitted.getTarget());
                }
            }
            
        };
        editGenre.setVisible(session.isAuthorized());
        this.add(editGenre);
        
        String deleteMessage = new StringResourceModel("GenrePage.deleteGenre.confirmation.message", this, null).getObject();
        ConfirmationLink<IGenreDTO> deleteGenre = new ConfirmationLink<IGenreDTO>(ComponentIDs.DELETE_GENRE_LINK, deleteMessage) {

            @Override
            public void onClick(AjaxRequestTarget target) {
                try {
                    IUser user = MusicLibrarySession.get().getUser();
                    String userName = user != null ? user.getUserName() : null;
                    GenrePage.this.genreService.delete(genre, userName);
                    this.setResponsePage(SearchPage.class);
                } catch (Exception ex) {
                    String errorMessage = new StringResourceModel("database.delete.error", this, null).getObject();
                    target.appendJavaScript("alert('" + errorMessage + "');");
                }
            }
        };
        deleteGenre.setVisible(session.isAuthorized());
        this.add(deleteGenre);
    }
    
    private List<IAlbumDTO> getAlbums(IGenreDTO genre) {
        List<ISongDTO> songs = this.songService.getByGenre(genre);
        List<IAlbumDTO> albums = new ArrayList<IAlbumDTO>();
        for (final ISongDTO song : songs) {
            if (!albums.contains(song.getAlbum())) {
                albums.add(song.getAlbum());
            }
        }
        Collections.sort(albums, new Comparator<IAlbumDTO>() {
            private Collator collator = Collator.getInstance(GenrePage.this.getLocale());
            @Override
            public int compare(IAlbumDTO o1, IAlbumDTO o2) {
                return this.collator.compare(o1.getTitle(), o2.getTitle());
            }
        });
        return albums;
    }
    
    /** Identifiers of added components. */
    private static final class ComponentIDs {
        
        private static final String GENRE_NAME = "genreName";
        private static final String ALBUMS_VIEW = "albumsView";
        private static final String ALBUM_LINK = "albumLink";
        private static final String ALBUM_LINK_NAME = "albumLinkName";
        
        private static final String EDIT_GENRE_MODAL = "editGenreModal";
        private static final String EDIT_GENRE_MODAL_LINK = "editGenreModalLink";
        
        private static final String DELETE_GENRE_LINK = "deleteGenreLink";
    }
}